package com.eastfair.pay.chinaums.CScanB;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.eastfair.pay.chinaums.common.utils.TimeUtil;
import com.eastfair.pay.dto.ChinaumsDTO;
import com.eastfair.pay.entity.QueryBody;
import com.eastfair.pay.enums.InstMidEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.time.LocalDateTime;

/**
 * @author kkqiao
 * c扫b账单状态查询接口
 * 说明：
 * 一个账单可能使用多种支付方式（某种支付方式支付失败，再使用第二种支付方式），这种情况下一
 * 个账单对应多个账单支付流水。本接口获取的是成功的那一笔流水的相关信息（仅可能有一笔支付成
 * 功）。若所有流水都支付失败，那么仅返回支付状态，而不返回支付目标系统及相关支付流水信息。
 *  测试环境：http://58.247.0.18:29015/v1/netpay/bills/query
 *  生产环境：https://api-mop.chinaums.com/v1/netpay/bills/query
 */
@Slf4j
@Component
public class CScanBQuery {


    @Value("${chinaums.appid}")
    private String appid;
    @Value("${chinaums.appkey}")
    private String appkey;
    @Value("${chinaums.cScanBQueryUrl}")
    private String url;
    @Value("${chinaums.mid}")
    private String mid;
    @Value("${chinaums.tid}")
    private String tid;

//    public static void main(String[] args) throws Exception{
//        //1. 组建请求报文
//        QueryBody reqBody = new QueryBody();
//        reqBody.requestTimestamp = "2019-08-14 17:30:55";
//        reqBody.mid = "898460107420248";
//        reqBody.tid = "00000001";
//        reqBody.instMid = "QRPAYDEFAULT";
//        reqBody.billNo = "1017106881";
//        reqBody.billDate = "2019-08-14";
//        System.out.println("request body:\n"+reqBody);
//
//        //2. 获取认证报文，timestamp为当前日期，老旧日期无法请求成功
//        String authorization = getAuthorization(appid,appkey,"20190814173000","nonce",reqBody.toString());
//        System.out.println("authorization:\n"+authorization);
//
//        //3. 发送http请求，并解析返回信息
//        String response = request(url,authorization,reqBody.toString());
//        System.out.println("response:\n"+response);
//    }



    public ChinaumsDTO query(String billNo,String billDate) throws Exception{
        //1. 组建请求报文
        QueryBody reqBody = new QueryBody();
        LocalDateTime now = LocalDateTime.now();
        reqBody.setRequestTimestamp(LocalDateTimeUtil.format(now, "yyyy-MM-dd HH:mm:ss"));
        String timestamp = TimeUtil.getTimestamp(now);
        reqBody.setMid(mid);
        reqBody.setTid(tid);
        reqBody.setInstMid(InstMidEnum.QRPAYDEFAULT.getCode());
        reqBody.setBillNo (billNo);
        reqBody.setBillDate(billDate);
        log.info("request body:\n" + reqBody);

        //2. 获取认证报文，timestamp为当前日期，老旧日期无法请求成功
        String authorization = getAuthorization(appid,appkey, timestamp,"nonce",reqBody.toString());
        log.info("authorization:\n"+authorization);

        //3. 发送http请求，并解析返回信息
        String response = request(url,authorization,reqBody.toString());
        log.info("response:\n"+response);
        ChinaumsDTO chinaumsDTO = new ChinaumsDTO();
        chinaumsDTO.setAuthorization(authorization);
        chinaumsDTO.setUrl(url);
        chinaumsDTO.setQueryBody(reqBody);
        chinaumsDTO.setResponse(response);
        chinaumsDTO.setInstMid(reqBody.getInstMid());
        return chinaumsDTO;
    }

    /**
     * 发送http请求
     * @param url 请求url
     * @param authorization 认证报文
     * @param reqBody  请求体
     * @return response
     */
    static String request(String url, String authorization, String reqBody){
        String response = "";
        PrintWriter out = null;
        BufferedReader in = null;
        try{
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            HttpURLConnection httpUrlConnection = (HttpURLConnection) conn;
            httpUrlConnection.setRequestProperty("Content-Type", "application/json");
            httpUrlConnection.setRequestProperty("authorization",authorization);
            httpUrlConnection.setDoOutput(true);
            httpUrlConnection.setDoInput(true);
            out = new PrintWriter(httpUrlConnection.getOutputStream());
            out.write(reqBody);
            out.flush();
            httpUrlConnection.connect();
            in = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                response += line;
            }
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            try {
                if (out != null) { out.close();}
                if (in != null) { in.close();}
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return response;
    }

    /**
     * 获取签名头
     * @param appid
     * @param appkey
     * @param timestamp 格式:"yyyyMMddHHmmss"
     * @param nonce 随机字符串，
     * @param body 请求体
     * @return authorization 认证报文
     * @throws Exception
     */
    static String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body) throws Exception {
        byte[] data = body.getBytes("utf-8");
        InputStream is = new ByteArrayInputStream(data);
        String testSH = DigestUtils.sha256Hex(is);
        String s1 = appid+timestamp+nonce+testSH;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(appkey.getBytes("utf-8"),"HmacSHA256"));
        byte[] localSignature = mac.doFinal(s1.getBytes("utf-8"));
        String localSignatureStr = Base64.encodeBase64String(localSignature);
        return  "OPEN-BODY-SIG AppId="+"\""+appid+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\"";
    }

}
